home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.04 Apr 95 / TreeAppƒ / Eric's C++ Libraries / Interface Classes / CPPScrollArea.cp < prev    next >
Encoding:
Text File  |  1996-04-04  |  31.2 KB  |  1,153 lines  |  [TEXT/KAHL]

  1. /********************************************************* DEFINITION
  2.     DATE:    10/17/93
  3.     AUTHOR: Eric R. Rosé
  4.     
  5.     CLASS:  CPPScrollArea
  6.     
  7.     SUPERCLASS: CPPVisualObject
  8.     
  9.         This C++ class manages a scrollable area
  10.     
  11. ********************************************************************/
  12.  
  13.  
  14. #include <CPPWindow.h>
  15. #include <CPPScrollArea.h>
  16. #include <Commands.h>
  17. #include <mathTools.h>
  18.  
  19. /*-----------------------------------------------------------------*/
  20. /*---------------------- CALLBACK VARIABLES -----------------------*/
  21. /*-----------------------------------------------------------------*/
  22.  
  23.     // Initialize the class member variables used in the callbacks
  24.     CPPScrollArea *CPPScrollArea::gCurrentArea = NULL;
  25.     ControlHandle CPPScrollArea::gVScroll = NULL;
  26.     ControlHandle CPPScrollArea::gHScroll = NULL;
  27.  
  28. /*-----------------------------------------------------------------*/
  29. /*-------------------------- GLOBALS ------------------------------*/
  30. /*-----------------------------------------------------------------*/
  31.  
  32.     extern    Rect        kEmptyRect;
  33.  
  34. /*-----------------------------------------------------------------*/
  35. /*------------------------ PUBLIC METHODS -------------------------*/
  36. /*-----------------------------------------------------------------*/
  37.  
  38.  
  39.     CPPScrollArea::CPPScrollArea (CPPWindow *OurWindow,
  40.                                   Rect *ViewArea,
  41.                                   Rect *DestArea,
  42.                                   Boolean UseHScroll,
  43.                                   Boolean UseVScroll,
  44.                                   short hStep, short vStep) :
  45.                    CPPVisualObject (OurWindow, ViewArea, TRUE, FALSE)
  46.     {
  47.         MakeCPPScrollArea (OurWindow, ViewArea, DestArea, 
  48.                            UseHScroll, UseVScroll, hStep, vStep);
  49.     
  50.     }
  51.  
  52. /*-----------------------------------------------------------------*/
  53.           
  54.     CPPScrollArea::CPPScrollArea (CPPWindow *OurWindow,
  55.                                   Boolean UseHScroll,
  56.                                   Boolean UseVScroll,
  57.                                   short hStep, short vStep) :
  58.                 CPPVisualObject (OurWindow,
  59.                                  &((OurWindow->GetWindow())->portRect), 
  60.                                    TRUE, FALSE)
  61.     {
  62.         Rect    ViewRect;
  63.         Rect    DestRect;
  64.  
  65.         if (OurWindow)
  66.           {
  67.               ViewRect = (OurWindow->GetWindow())->portRect;
  68.               SetRect (&DestRect, 0, 0, kPageWidth, kPageHeight);
  69.             MakeCPPScrollArea (OurWindow, &ViewRect, &DestRect, 
  70.                                UseHScroll, UseVScroll, hStep, vStep);
  71.           }
  72.     }
  73.  
  74. /*-----------------------------------------------------------------*/
  75.     
  76.     CPPScrollArea::~CPPScrollArea (void)
  77.     {
  78.     
  79.     }
  80.     
  81. /*-----------------------------------------------------------------*/
  82.  
  83.     Boolean    CPPScrollArea::Member (char *className)
  84.     {
  85.         if (strcmp(className, CPPScrollArea::ClassName()) == 0)
  86.           return TRUE;
  87.         else
  88.           return CPPVisualObject::Member(className);
  89.     }
  90.     
  91. /*-----------------------------------------------------------------*/
  92.  
  93.     char     *CPPScrollArea::ClassName (void)
  94.     {
  95.         return "CPPScrollArea";
  96.     }
  97.  
  98. /*-----------------------------------------------------------------*/
  99.  
  100.     Boolean    CPPScrollArea::DoCommand (short commandID)
  101.     /* do a command associated with a menu */
  102.     {
  103.         switch (commandID) {
  104.             case kCmdCut :
  105.                 DoCut();
  106.                 break;
  107.             case kCmdCopy :    
  108.                 DoCopy();
  109.                 break;
  110.             case kCmdPaste :
  111.                 DoPaste();
  112.                 break;
  113.             case kCmdSelectAll :
  114.                 DoSelectAll();
  115.                 break;
  116.             case kCmdClear :
  117.                 DoClear();
  118.                 break;
  119.             default:
  120.                 return CPPVisualObject::DoCommand(commandID);
  121.                 break;
  122.         }
  123.         
  124.         return TRUE;
  125.     }
  126.  
  127. /*-----------------------------------------------------------------*/
  128.  
  129.     void    CPPScrollArea::DoCut (void)
  130.     /* cut the currently selected contents */
  131.     /* SUBCLASS SHOULD OVERRIDE */
  132.     {
  133.     
  134.     }
  135.  
  136. /*-----------------------------------------------------------------*/
  137.  
  138.     void    CPPScrollArea::DoCopy (void)
  139.     /* copy the currently selected contents */
  140.     /* SUBCLASS SHOULD OVERRIDE */
  141.     {
  142.     
  143.     }
  144.  
  145. /*-----------------------------------------------------------------*/
  146.  
  147.     void    CPPScrollArea::DoPaste (void)
  148.     /* paste new data into the area */
  149.     /* SUBCLASS SHOULD OVERRIDE */
  150.     {
  151.     
  152.     }
  153.  
  154. /*-----------------------------------------------------------------*/
  155.  
  156.     void    CPPScrollArea::DoClear (void)
  157.     /* clear the currently selected contents */
  158.     /* SUBCLASS SHOULD OVERRIDE */
  159.     {
  160.         
  161.     }
  162.  
  163. /*-----------------------------------------------------------------*/
  164.  
  165.     void    CPPScrollArea::DoSelectAll (void)
  166.     /* select the entire scroll area */
  167.     {
  168.         RemoveSelection();
  169.         
  170.         MakeSelection (&this->destRect);
  171.     }
  172.  
  173. /*-----------------------------------------------------------------*/
  174.  
  175.     void    CPPScrollArea::RemoveSelection(void)
  176.     /* forget about the current selection */
  177.     {        
  178.         if (this->hasSelection)
  179.           {
  180.               HiliteSelection(FALSE);
  181.               this->selRect = kEmptyRect;
  182.               this->hasSelection = FALSE;
  183.           }
  184.     }
  185.         
  186. /*-----------------------------------------------------------------*/
  187.  
  188.     void    CPPScrollArea::MakeSelection (Rect *newSelection)
  189.     /* create a new selection area; deselect any which previously */
  190.     /* existed */
  191.     {
  192.         if (this->hasSelection)
  193.           RemoveSelection();
  194.         this->selRect = *newSelection;
  195.         this->hasSelection = TRUE;
  196.         HiliteSelection(TRUE);
  197.     }
  198.  
  199. /*-----------------------------------------------------------------*/
  200.  
  201.     void    CPPScrollArea::HiliteSelection (Boolean doHilight)
  202.     /* SUBCLASS SHOULD OVERRIDE */
  203.     /* Turn the hilighting of the selection on or off depending on */
  204.     /* the value of doHilight */
  205.     {
  206.         
  207.     }
  208.     
  209. /*-----------------------------------------------------------------*/
  210.  
  211.     void    CPPScrollArea::IdleSelection (void)
  212.     /* Perform whatever periodic updating is needed to hilight */
  213.     /* the selection */
  214.     /* SUBCLASS SHOULD OVERRIDE */
  215.     {
  216.         
  217.     }
  218.  
  219. /*-----------------------------------------------------------------*/
  220.  
  221.     void    CPPScrollArea::Activate (Boolean nowActive)
  222.     /* activate or deactivate the controls in the scroll area */
  223.     {
  224.         short    HiliteValue = (nowActive) ? 0 : 255;
  225.         
  226.         CPPVisualObject::Activate(nowActive);
  227.         
  228.         AdjustScrollBar();
  229.         
  230.         if (this->VScroll)
  231.           HiliteControl (this->VScroll, HiliteValue);
  232.         if (this->HScroll)
  233.           HiliteControl (this->HScroll, HiliteValue);
  234.     }
  235.     
  236. /*-----------------------------------------------------------------*/
  237.     
  238.     Boolean CPPScrollArea::DoClick (EventRecord *theEvent)
  239.     /* handle a click in the scroll area; return TRUE if we */
  240.     /* actually handle it */
  241.     {
  242.         WindowPtr    theWindow;
  243.         short        code, part;
  244.         ControlHandle    hitControl;
  245.         Point        myPt = theEvent->where;
  246.         Rect        selRect;
  247.         Boolean        shiftDown = (theEvent->modifiers & shiftKey) ? TRUE : FALSE;
  248.         
  249.         if (!IsVisible()) return FALSE;
  250.         
  251.           code = FindWindow(theEvent->where, &theWindow);
  252.           if (theWindow == this->owningWindow)
  253.             {
  254.               Global2Local (&myPt);
  255.             part = FindControl(myPt, theWindow, &hitControl);
  256.             
  257.             // now respond to the click
  258.             if (hitControl)        // if they clicked in a scrollbar
  259.               {
  260.                 if (hitControl == this->HScroll)
  261.                   {
  262.                     DoHScroller (myPt, part);
  263.                     return TRUE;
  264.                   }
  265.                 else
  266.                 if (hitControl ==  this->VScroll)
  267.                   {
  268.                     DoVScroller (myPt, part);
  269.                     return TRUE;
  270.                   }
  271.                 else
  272.                   return FALSE;
  273.               }
  274.             else                // if they clicked in the scroll area
  275.               {
  276.                   if (PtInRect (myPt, &this->areaRect))
  277.                     {
  278.                           gVScroll = this->VScroll;
  279.                           gHScroll = this->HScroll;
  280.                           gCurrentArea = this;
  281.                         Local2Area (&myPt);
  282.                       return DoScrollAreaClick(myPt, theEvent->modifiers, &selRect);
  283.                     }
  284.                   else
  285.                     return FALSE;
  286.               }    
  287.             }
  288.     }
  289.     
  290. /*-----------------------------------------------------------------*/
  291.     
  292.     Boolean    CPPScrollArea::DoScrollAreaClick (Point clickPt, short modifiers, 
  293.                                               Rect *selRect)
  294.     /* handle a click in the scroll area; clickPt is in area coordinates */
  295.     /* a rectangle encompassing the selected area is returned in selRect */
  296.     /* (this is in area coordinates) */
  297.     /* SUBCLASS SHOULD OVERRIDE */
  298.     {
  299.         Point    startPt = clickPt, 
  300.                 EndPt;
  301.         PenState    OldState;
  302.         
  303.         SetRect (selRect, -1, -1, -1, -1);
  304.                 
  305.         // default behavior; scroll the area automatically as long
  306.         // as the mouse is down
  307.         this->isDragging = TRUE;
  308.         this->anchorPoint = this->currentPoint = this->lastPoint = clickPt;
  309.         
  310.         while (StillDown())
  311.           AutoScroll();
  312.         this->isDragging = FALSE;
  313.           
  314.         Pt2Rect (this->anchorPoint, this->currentPoint, selRect);
  315.         if (this->needsErase)
  316.           {
  317.             // erase the last frame
  318.             AdjustCoordinates();
  319.             GetPenState (&OldState);
  320.             PenMode (patXor);
  321.             PenPat (gray);
  322.             FrameRect (selRect);
  323.             SetPenState (&OldState);
  324.             RestoreCoordinates();
  325.             this->needsErase = FALSE;
  326.           }
  327.                   
  328.         return TRUE;
  329.     }
  330.  
  331. /*-----------------------------------------------------------------*/
  332.     
  333.     void    CPPScrollArea::DoIdle (void)
  334.     {
  335.         if (this->hasSelection)
  336.           IdleSelection ();
  337.     }
  338.     
  339. /*-----------------------------------------------------------------*/
  340.  
  341.     Rect    *CPPScrollArea::GetAreaRect (void)
  342.     {
  343.         return &this->areaRect;
  344.     }
  345.  
  346. /*-----------------------------------------------------------------*/
  347.  
  348.     Rect    *CPPScrollArea::GetBounds (void)
  349.     /* return a rectangle in window coordinates which encloses */
  350.     /* the whole visible scroll area and its controls*/
  351.     {
  352.         this->bounds = kEmptyRect;
  353.         
  354.         if (this->isVisible)
  355.           {
  356.               this->bounds = this->areaRect;                
  357.             if (this->HScroll)
  358.               UnionRect (&((**this->HScroll).contrlRect), &this->bounds, &this->bounds);
  359.             if (this->VScroll)
  360.               UnionRect (&((**this->VScroll).contrlRect), &this->bounds, &this->bounds);
  361.           
  362.               if (!this->VScroll)
  363.                 {
  364.                   if (!this->HScroll)
  365.                     InsetRect(&this->bounds, -1, -1);
  366.                   else
  367.                     this->bounds.top--;  
  368.                 }
  369.               else
  370.                 {
  371.                     if (!this->HScroll)
  372.                       this->bounds.left--;
  373.                 }
  374.           }
  375.  
  376.         return &this->bounds;
  377.     }
  378.     
  379. /*-----------------------------------------------------------------*/
  380.  
  381.     void    CPPScrollArea::DrawContents (void)
  382.     /* Draw the data in the window */
  383.     /* SUBCLASS MUST OVERRIDE */
  384.     {
  385.  
  386.     }
  387.     
  388. /*-----------------------------------------------------------------*/
  389.  
  390.     void    CPPScrollArea::AdjustCoordinates (void)
  391.     /* call this routine before drawing the contents of the */
  392.     /* scroll area to set the clipping region and the origin */
  393.     {
  394.         Rect            tempRect;
  395.         
  396.         this->oldClip = NewRgn();
  397.         this->newClip = NewRgn();
  398.         
  399.         // set the origin so the contents can drawn naturally
  400.         SetOrigin(this->viewRect.left-this->areaRect.left, 
  401.                   this->viewRect.top-this->areaRect.top);
  402.  
  403.         // clip drawing to the visible area
  404.         GetClip (oldClip);
  405.         tempRect = this->viewRect;
  406.         RectRgn (newClip, &tempRect);
  407.         SectRgn (newClip, oldClip, newClip);
  408.         SetClip (newClip);
  409.     }
  410.  
  411. /*-----------------------------------------------------------------*/
  412.  
  413.     void    CPPScrollArea::RestoreCoordinates (void)
  414.     /* call this routine after drawing the contents of the */
  415.     /* scroll area to restore the clipping region and the origin */
  416.     {
  417.         SetClip (oldClip);
  418.         DisposeRgn(oldClip);
  419.         DisposeRgn(newClip);
  420.         SetOrigin(0, 0);
  421.     }
  422.  
  423. /*-----------------------------------------------------------------*/
  424.  
  425.     void    CPPScrollArea::Draw (void)
  426.     /* set the origin and clipping rect and call the user routine */
  427.     /* to draw the contents of the scroll area */
  428.     {
  429.         Rect        tempRect = *GetBounds();
  430.         PenState    OldState;
  431.  
  432.         if (this->owningWindow && this->IsVisible())
  433.           {
  434.             // draw the frame and the scrollbars
  435.             if (this->VScroll)
  436.               Draw1Control (this->VScroll);
  437.             if (this->HScroll)
  438.               Draw1Control (this->HScroll);
  439.             FrameRect (&tempRect);
  440.     
  441.             // adjust the clip region and coordinate system
  442.             AdjustCoordinates();
  443.             
  444.             // call the user routines to draw the contents and selection
  445.             DrawContents();
  446.             
  447.             if (this->hasSelection)
  448.               HiliteSelection(TRUE);
  449.             
  450.             // restore the clip region and coordinate system
  451.             RestoreCoordinates();
  452.           }          
  453.     }
  454.     
  455. /*-----------------------------------------------------------------*/
  456.  
  457.     void    CPPScrollArea::MakeVisible (Boolean nowVisible)
  458.     {
  459.         Rect    boundsRect = *GetBounds();
  460.     
  461.         // exit if it is already in the desired state
  462.         if (nowVisible == IsVisible())
  463.           return;
  464.         
  465.         CPPVisualObject::MakeVisible (nowVisible);
  466.  
  467.         // if it is currently invisible, erase it;
  468.         // in either case, invalidate the area to force a redraw
  469.         if (!IsVisible())
  470.           {
  471.             EraseRect (&boundsRect);
  472.             if (this->VScroll)
  473.               HideControl(VScroll);
  474.             if (this->HScroll)
  475.               HideControl(HScroll);
  476.           }
  477.         else
  478.           {
  479.             if (this->VScroll)
  480.               ShowControl(VScroll);
  481.             if (this->HScroll)
  482.               ShowControl(HScroll);
  483.             this->Draw();
  484.           }
  485.           
  486.         InvalRect(&boundsRect);
  487.     }
  488.  
  489. /*-----------------------------------------------------------------*/
  490.  
  491.     void    CPPScrollArea::TargetHilite (Boolean makeTarget)
  492.     /* do any hiliting necessary to indicate that the scroll area is */
  493.     /* now the target */
  494.     /* SUBCLASS MAY OVERRIDE */
  495.     {
  496.         this->Activate(makeTarget);
  497.         
  498.         CPPVisualObject::TargetHilite(makeTarget);
  499.     }
  500.  
  501. /*-----------------------------------------------------------------*/
  502.                                    
  503.     void    CPPScrollArea::SetHorizontalStep (short stepSize)
  504.     /* change the step size of the horizontal scroll bar; adjust */
  505.     /* the current value of the scrollbar as necessary */
  506.     {
  507.         short    oldValue, oldMax, newMax;
  508.         
  509.         if (this->hStep != stepSize)
  510.           {
  511.               this->hStep = stepSize;
  512.               if (this->HScroll)
  513.                 {
  514.                     oldValue = GetCtlValue(this->HScroll);
  515.                     oldMax = GetCtlMax(this->HScroll);
  516.                     
  517.                     SetCtlMax (this->HScroll, newMax = AreaWidth());
  518.                     SetCtlValue (this->HScroll, newMax * oldValue / oldMax);
  519.                 }
  520.           }
  521.     }
  522.  
  523. /*-----------------------------------------------------------------*/
  524.  
  525.     void    CPPScrollArea::SetVerticalStep    (short stepSize)
  526.     /* change the step size of the vertical scroll bar; adjust */
  527.     /* the current value of the scrollbar as necessary */
  528.     {
  529.         short    oldValue, oldMax, newMax;
  530.         
  531.         if (this->vStep != stepSize)
  532.           {
  533.               this->vStep = stepSize;
  534.               if (this->VScroll)
  535.                 {
  536.                     oldValue = GetCtlValue(this->VScroll);
  537.                     oldMax = GetCtlMax(this->VScroll);
  538.                     
  539.                     SetCtlMax (this->VScroll, newMax = AreaHeight());
  540.                     SetCtlValue (this->VScroll, newMax * oldValue / oldMax);
  541.                 }
  542.           }
  543.     }
  544.  
  545. /*-----------------------------------------------------------------*/
  546.  
  547.     void     CPPScrollArea::MoveScrollArea (void)
  548.     {
  549.         long    ScrollValue,
  550.                 height, i, j, 
  551.                 HScrollDiff = 0, VScrollDiff = 0,
  552.                 OldScroll, NewScroll;
  553.         RgnHandle    updateRgn = NewRgn(),
  554.                     oldClipRgn = NewRgn();
  555.         Rect    tempRect = this->areaRect;
  556.                 
  557.         if (this->VScroll)
  558.           {
  559.               OldScroll = this->viewRect.top - this->destRect.top;
  560.               ScrollValue = GetCtlValue (this->VScroll);
  561.               NewScroll = ScrollValue * this->vStep;
  562.               VScrollDiff = OldScroll - NewScroll;
  563.           }          
  564.  
  565.         if (this->HScroll)
  566.           {
  567.               OldScroll = this->viewRect.left - this->destRect.left;
  568.               ScrollValue = GetCtlValue (this->HScroll);
  569.               NewScroll = ScrollValue * this->hStep;
  570.               HScrollDiff = OldScroll - NewScroll;
  571.           }          
  572.  
  573.         // do the scrolling, if any is required
  574.         if (VScrollDiff + HScrollDiff != 0)
  575.           ScrollRect(&tempRect, HScrollDiff, VScrollDiff, updateRgn);
  576.         OffsetRect (&this->viewRect, -HScrollDiff, -VScrollDiff);
  577.         OffsetRgn (updateRgn, viewRect.left - areaRect.left, 
  578.                               viewRect.top - areaRect.top); 
  579.         
  580.         
  581.         GetClip (oldClipRgn);
  582.         SectRgn (updateRgn, oldClipRgn, updateRgn);
  583.         SetClip (updateRgn);
  584.           
  585.         this->Draw();
  586.         
  587.         SetClip (oldClipRgn);
  588.         DisposeRgn(updateRgn);
  589.         DisposeRgn(oldClipRgn);
  590.     }
  591.  
  592. /*-----------------------------------------------------------------*/
  593.  
  594.     void    CPPScrollArea::ScrollLeft (short steps)
  595.     /* let another class ask us to scroll the area to the left */
  596.     {
  597.         ControlHandle    theControl = this->HScroll;
  598.         
  599.         if (theControl && (GetCtlValue(theControl) - steps >= GetCtlMin(theControl)))
  600.           {
  601.               SetCtlValue (theControl, GetCtlValue (theControl)-steps);
  602.               this->MoveScrollArea();
  603.           }    
  604.     }
  605.  
  606. /*-----------------------------------------------------------------*/
  607.  
  608.     void    CPPScrollArea::ScrollRight (short steps)
  609.     /* let another class ask us to scroll the area to the right */
  610.     {
  611.         ControlHandle    theControl = this->HScroll;
  612.         
  613.         if (theControl && (GetCtlValue(theControl) + steps <= GetCtlMax(theControl)))
  614.           {
  615.               SetCtlValue (theControl, GetCtlValue (theControl)+steps);
  616.               this->MoveScrollArea();
  617.           }    
  618.     }
  619.  
  620. /*-----------------------------------------------------------------*/
  621.  
  622.     void    CPPScrollArea::ScrollUp (short steps)
  623.     /* let another class ask us to scroll the area down */
  624.     {
  625.         ControlHandle    theControl = this->VScroll;
  626.         
  627.         if (theControl && (GetCtlValue(theControl) - steps >= GetCtlMin(theControl)))
  628.           {
  629.               SetCtlValue (theControl, GetCtlValue (theControl)-steps);
  630.               this->MoveScrollArea();
  631.           }    
  632.     }
  633.  
  634. /*-----------------------------------------------------------------*/
  635.  
  636.     void    CPPScrollArea::ScrollDown (short steps)
  637.     /* let another class ask us to scroll the area up */
  638.     {
  639.         ControlHandle    theControl = this->HScroll;
  640.         
  641.         if (theControl && (GetCtlValue(theControl) + steps <= GetCtlMax(theControl)))
  642.           {
  643.               SetCtlValue (theControl, GetCtlValue (theControl)+steps);
  644.               this->MoveScrollArea();
  645.           }    
  646.     }
  647.  
  648. /*-----------------------------------------------------------------*/
  649. /*---------------------- PROTECTED METHODS ------------------------*/
  650. /*-----------------------------------------------------------------*/
  651.  
  652.     void    CPPScrollArea::ResizeContent (short newWidth, short newHeight)
  653.     {
  654.         Rect    VCRect, HCRect, GrowRect, ViewRect, DestRect;
  655.         Rect    PRect;
  656.         
  657.         if (this->owningWindow)
  658.           {
  659.               // resize the actual on-screen area;
  660.               this->areaRect.right = this->areaRect.left +
  661.                   newWidth - ((this->VScroll) ? 15 : 0);
  662.               this->areaRect.bottom = this->areaRect.top +
  663.                   newHeight - ((this->HScroll) ? 15 : 0);
  664.           
  665.               // set the new size of the view area
  666.               this->viewRect.right = this->viewRect.left + 
  667.                   (this->areaRect.right - this->areaRect.left);
  668.               this->viewRect.bottom = this->viewRect.top + 
  669.                   (this->areaRect.bottom - this->areaRect.top);
  670.                             
  671.               // move and resize the controls
  672.               if (this->HScroll)
  673.                 {
  674.                     HideControl (this->HScroll);
  675.                     MoveControl (this->HScroll, this->areaRect.left-1, this->areaRect.bottom);
  676.                     SizeControl (this->HScroll, (this->areaRect.right - this->areaRect.left) + 2, 16);
  677.                     ShowControl (this->HScroll);
  678.                 }
  679.  
  680.               if (this->VScroll)
  681.                 {
  682.                     HideControl (this->VScroll);
  683.                     MoveControl (this->VScroll, this->areaRect.right, this->areaRect.top-1);
  684.                     SizeControl (this->VScroll, 16, (this->areaRect.bottom - this->areaRect.top) + 2);
  685.                     ShowControl (this->VScroll);
  686.                 }
  687.                             
  688.               // adjust the positions of everything
  689.               if (viewRect.right > destRect.right)
  690.                 OffsetRect (&this->viewRect, destRect.right - viewRect.right, 0);
  691.               if (viewRect.bottom > destRect.bottom)
  692.                 OffsetRect (&this->viewRect, 0, destRect.bottom - viewRect.bottom);
  693.               AdjustScrollBar();
  694.           }
  695.     }
  696.     
  697. /*-----------------------------------------------------------------*/
  698.  
  699.     void    CPPScrollArea::MoveContent (short newH, short newV)
  700.     {
  701.         Rect        vRect, dRect, bRect = *GetBounds();
  702.         short        deltaH = newH - bRect.left,
  703.                      deltaV = newV - bRect.top;
  704.             
  705.         // move the visible area
  706.         OffsetRect (&this->areaRect, deltaH, deltaV);
  707.         
  708.         // move the vertical scroll bar
  709.         if (this->VScroll)
  710.           {
  711.               vRect = (*this->VScroll)->contrlRect;
  712.               MoveControl (this->VScroll, vRect.left + deltaH, 
  713.                                            vRect.top + deltaV);
  714.           }
  715.         
  716.         // move the horizontal scroll bar
  717.         if (this->HScroll)
  718.           {
  719.               dRect = (*this->HScroll)->contrlRect;
  720.               MoveControl (this->HScroll, dRect.left + deltaH, 
  721.                                            dRect.top + deltaV);
  722.           }
  723.     }
  724.  
  725. /*-----------------------------------------------------------------*/
  726. /*----------------------- PRIVATE METHODS -------------------------*/
  727. /*-----------------------------------------------------------------*/
  728.  
  729.     pascal void CPPScrollArea::Scroll_Up (ControlHandle theControl, short ctlPart)
  730.     /* this method serves as a callback routine for TrackControl; */
  731.     /* It forces the area to scroll up 1 line */
  732.     {
  733.         if (theControl && (GetCtlValue(theControl) - 1 >= GetCtlMin(theControl)))
  734.           {
  735.               SetCtlValue (theControl, GetCtlValue (theControl)-1);
  736.               gCurrentArea->MoveScrollArea();
  737.           }    
  738.     }
  739.  
  740. /*-----------------------------------------------------------------*/
  741.  
  742.     pascal void CPPScrollArea::Scroll_Down (ControlHandle theControl, 
  743.                                         short ctlPart)
  744.     /* this method serves as a callback routine for TrackControl; */
  745.     /* It forces the area to scroll down 1 line */
  746.     {
  747.         if (theControl && (GetCtlValue(theControl) + 1 <= GetCtlMax(theControl)))
  748.           {
  749.               SetCtlValue (theControl, GetCtlValue (theControl)+1);
  750.               gCurrentArea->MoveScrollArea();
  751.           }    
  752.     }
  753.  
  754. /*-----------------------------------------------------------------*/
  755.  
  756.     pascal void CPPScrollArea::Scroll_Left (ControlHandle theControl, 
  757.                                         short ctlPart)
  758.     /* this method serves as a callback routine for TrackControl; */
  759.     /* It forces the area to scroll left 1 line */
  760.     {
  761.         if (theControl && (GetCtlValue(theControl) - 1 >= GetCtlMin(theControl)))
  762.           {
  763.               SetCtlValue (theControl, GetCtlValue (theControl)-1);
  764.               gCurrentArea->MoveScrollArea();
  765.           }    
  766.     }
  767.  
  768. /*-----------------------------------------------------------------*/
  769.  
  770.     pascal void CPPScrollArea::Scroll_Right (ControlHandle theControl, 
  771.                                         short ctlPart)
  772.     /* this method serves as a callback routine for TrackControl; */
  773.     /* It forces the area to scroll right 1 line */
  774.     {
  775.         if (theControl && (GetCtlValue(theControl) + 1 <= GetCtlMax(theControl)))
  776.           {
  777.               SetCtlValue (theControl, GetCtlValue (theControl)+1);
  778.               gCurrentArea->MoveScrollArea();
  779.           }    
  780.     }
  781.  
  782. /*-----------------------------------------------------------------*/
  783.  
  784.     void    CPPScrollArea::Area2Local (Point *thePoint)
  785.     /* convert from scroll area coordinates to window coordinates */
  786.     {
  787.         thePoint->h += this->areaRect.left;
  788.         if (this->HScroll)
  789.           thePoint->h -= GetCtlValue(this->HScroll) * this->hStep;
  790.         thePoint->v += this->areaRect.top;
  791.         if (this->VScroll)
  792.           thePoint->v -= GetCtlValue(this->VScroll) * this->vStep;
  793.     }
  794.  
  795. /*-----------------------------------------------------------------*/
  796.  
  797.     void    CPPScrollArea::Local2Area (Point *thePoint)
  798.     /* convert from window coordinates to scroll area coordinates */
  799.     {
  800.         thePoint->h -= this->areaRect.left;
  801.         if (this->HScroll)
  802.           thePoint->h += GetCtlValue(this->HScroll) * this->hStep;
  803.         thePoint->v -= this->areaRect.top;
  804.         if (this->VScroll)
  805.           thePoint->v += GetCtlValue(this->VScroll) * this->vStep;
  806.     }
  807.  
  808. /*-----------------------------------------------------------------*/
  809.  
  810.     void    CPPScrollArea::Area2Global (Point *thePoint)
  811.     /* convert from scroll area coordinates to global coordinates */
  812.     {
  813.         WindowPtr    theWindow = this->owningWindow;
  814.  
  815.         if (theWindow)
  816.           {
  817.               // first convert it from area to local
  818.               Area2Local (thePoint);
  819.               // then convert from local to global
  820.               thePoint->h -= theWindow->portRect.left;
  821.               thePoint->v -= theWindow->portRect.top;
  822.           }
  823.     }
  824.  
  825. /*-----------------------------------------------------------------*/
  826.  
  827.     void    CPPScrollArea::Global2Area (Point *thePoint)
  828.     /* convert from global coordinates to scroll area coordinates */
  829.     {
  830.         WindowPtr    theWindow = this->owningWindow;
  831.         
  832.         if (theWindow)
  833.           {
  834.               // first convert from global to local
  835.               thePoint->h += theWindow->portRect.left;
  836.               thePoint->v += theWindow->portRect.top;
  837.               // then convert from local to area
  838.               Local2Area (thePoint);
  839.           }    
  840.     }
  841.  
  842. /*-----------------------------------------------------------------*/
  843.  
  844.     void CPPScrollArea::AutoScroll (void)
  845.     /* This routine will cause the area to scroll to follow the */
  846.     /* mouse */
  847.     {
  848.         Rect        currRect, lastRect;
  849.         RgnHandle    prevRgn, dRgn, UtilRgn, oldVis;
  850.         PenState    OldState;
  851.         Point        mouseLoc;
  852.         long        tempLong;
  853.         
  854.         // get the area currently being displayed
  855.         // we will use this to limit the 'prev' rect
  856.         AdjustCoordinates();
  857.         oldVis = NewRgn();
  858.         RectRgn (oldVis, &this->viewRect);
  859.         RestoreCoordinates();
  860.         
  861.         GetMouse (&mouseLoc);
  862.         
  863.         // scroll the window if we are out of bounds
  864.         if (mouseLoc.v < this->areaRect.top+2)
  865.           Scroll_Up (gVScroll, inUpButton);
  866.         else
  867.           if (mouseLoc.v > this->areaRect.bottom-2)
  868.             Scroll_Down (gVScroll, inDownButton);
  869.  
  870.         if (mouseLoc.h > this->areaRect.right-2)
  871.           Scroll_Right (gHScroll, inDownButton);
  872.         else
  873.           if (mouseLoc.h < this->areaRect.left+2)
  874.             Scroll_Left (gHScroll, inUpButton);
  875.  
  876.         // get the current point in area coordinates
  877.         this->currentPoint = mouseLoc;
  878.         Local2Area (&this->currentPoint);
  879.  
  880.         // draw the selection marquee
  881.         if (this->isDragging && (!EqualPt(this->currentPoint, this->lastPoint)))
  882.           {
  883.             // adjust the clip region and coordinate system
  884.             AdjustCoordinates();
  885.             this->currentPoint.h = PINTORANGE(this->currentPoint.h, this->viewRect.left, this->viewRect.right);
  886.             this->currentPoint.v = PINTORANGE(this->currentPoint.v, this->viewRect.top, this->viewRect.bottom);
  887.             GetPenState(&OldState);
  888.  
  889.             Pt2Rect (this->anchorPoint, this->currentPoint, &currRect);
  890.             Pt2Rect (this->anchorPoint, this->lastPoint, &lastRect);
  891.                 
  892.             // Here we do a lot of work to prevent flashing of the selection rectangle
  893.             
  894.             UtilRgn = NewRgn();                
  895.             prevRgn = NewRgn();                // Construct region consisting of a    
  896.             dRgn = NewRgn();                //   one pixel thick outline of        
  897.             RectRgn(UtilRgn, &currRect);    //   the current selection rect        
  898.             CopyRgn(UtilRgn, dRgn);
  899.             InsetRgn(dRgn, 1, 1);
  900.             DiffRgn(UtilRgn, dRgn, UtilRgn);
  901.             
  902.             RectRgn(prevRgn, &lastRect);    // Construct region consisting of a    
  903.             CopyRgn(prevRgn, dRgn);            //   one pixel thick outline of        
  904.             InsetRgn(dRgn, 1, 1);            //   the previous selection rect    
  905.             DiffRgn(prevRgn, dRgn, prevRgn);
  906.             SectRgn(prevRgn, oldVis, prevRgn);
  907.             
  908.             // Get region which includes only those pixels that are NOT in both regions                    
  909.             XorRgn(UtilRgn, prevRgn, UtilRgn);
  910.             DisposeRgn(prevRgn);
  911.             DisposeRgn(dRgn);
  912.             
  913.             PenMode(patXor);                // Paint this new region in gray in    
  914.             PenPat(gray);                    //   Xor mode so pixels are flipped    
  915.             PaintRgn(UtilRgn);
  916.             DisposeRgn(UtilRgn);
  917.             this->lastPoint = this->currentPoint;
  918.             // adjust the clip region and coordinate system
  919.             SetPenState(&OldState);
  920.             RestoreCoordinates();
  921.             this->needsErase = TRUE;
  922.           }
  923.     
  924.         DisposeRgn(oldVis);
  925.     }
  926.  
  927. /*-----------------------------------------------------------------*/
  928.  
  929.     void    CPPScrollArea::VPageScroll (long part, long direction)
  930.     /* Scroll the text 1 page either up or down */
  931.     {
  932.         Point    tempPt;
  933.         short    newValue, page;
  934.         
  935.         if (this->VScroll)
  936.           {
  937.               GetMouse (&tempPt);
  938.               while (StillDown())
  939.                 {
  940.                     if (TestControl(this->VScroll, tempPt) == part)
  941.                       {
  942.                           page = direction * (ViewHeight() - 1);
  943.                           newValue = GetCtlValue (this->VScroll) + page;
  944.                           SetCtlValue (this->VScroll, newValue);
  945.                           MoveScrollArea();
  946.                       }
  947.                     GetMouse (&tempPt);
  948.                 }    
  949.           }
  950.     }
  951.     
  952. /*-----------------------------------------------------------------*/
  953.  
  954.     void    CPPScrollArea::HPageScroll (long part, long direction)
  955.     /* Scroll the text 1 page either left or right */
  956.     {
  957.         Point    tempPt;
  958.         short    newValue, page;
  959.         
  960.         if (this->HScroll)
  961.           {
  962.               GetMouse (&tempPt);
  963.               while (StillDown())
  964.                 {
  965.                     if (TestControl(this->HScroll, tempPt) == part)
  966.                       {
  967.                           page = direction * (ViewWidth()-1);
  968.                           newValue = GetCtlValue (this->HScroll) + page;
  969.                           SetCtlValue (this->HScroll, newValue);
  970.                           MoveScrollArea();
  971.                       }
  972.                     GetMouse (&tempPt);
  973.                 }    
  974.           }
  975.     }
  976.  
  977. /*-----------------------------------------------------------------*/
  978.  
  979.      long    CPPScrollArea::AreaWidth (void)
  980.      /* return the number of horizontal lines in the entire scroll area */
  981.      {
  982.          return ((this->destRect.right - this->destRect.left) / this->hStep);
  983.      }
  984.  
  985. /*-----------------------------------------------------------------*/
  986.  
  987.      long    CPPScrollArea::AreaHeight (void)
  988.       /* return the number of vertical lines in the entire scroll area */
  989.     {
  990.          return ((this->destRect.bottom - this->destRect.top) / this->vStep);
  991.      }
  992.  
  993. /*-----------------------------------------------------------------*/
  994.  
  995.      long    CPPScrollArea::ViewWidth (void)
  996.      /* return the number of horizontal lines in the visible scroll area */
  997.     {
  998.          return ((this->viewRect.right - this->viewRect.left) / this->hStep);
  999.      }
  1000.  
  1001. /*-----------------------------------------------------------------*/
  1002.  
  1003.      long    CPPScrollArea::ViewHeight (void)
  1004.       /* return the number of vertical lines in the visible scroll area */
  1005.      {
  1006.          return ((this->viewRect.bottom - this->viewRect.top) / this->vStep);
  1007.      }
  1008.  
  1009. /*-----------------------------------------------------------------*/
  1010.  
  1011.     void    CPPScrollArea::AdjustScrollBar (void)
  1012.     /* This procedure turns the scroll bars off if there are fewer */
  1013.     /* lines than space for lines, and turns them on if there are more */
  1014.     {        
  1015.         if (this->HScroll)
  1016.           SetCtlMax (this->HScroll, Max(0, AreaWidth() - ViewWidth()));
  1017.         if (this->VScroll)
  1018.           SetCtlMax (this->VScroll, Max(0, AreaHeight() - ViewHeight()));
  1019.     }
  1020.  
  1021. /*-----------------------------------------------------------------*/
  1022.  
  1023.     void CPPScrollArea::DoVScroller (Point clickPt, short part)
  1024.     /* Handle a click in the vertical scroll bar */
  1025.     {
  1026.         long    Result;
  1027.         
  1028.         gCurrentArea = this;
  1029.         
  1030.         if (this->VScroll)
  1031.           {
  1032.             switch (part) {
  1033.                 case inUpButton     :
  1034.                     Result = TrackControl(this->VScroll, clickPt, 
  1035.                                           (ProcPtr)Scroll_Up);
  1036.                     break;
  1037.                 case inDownButton    :
  1038.                     Result = TrackControl(this->VScroll, clickPt, 
  1039.                                           (ProcPtr)Scroll_Down);
  1040.                     break;
  1041.                 case inPageUp        :
  1042.                     VPageScroll (part, -1);
  1043.                     break;
  1044.                 case inPageDown        :
  1045.                     VPageScroll (part, 1);
  1046.                     break;
  1047.                 case inThumb        :
  1048.                     TrackControl (this->VScroll, clickPt, NULL);
  1049.                     MoveScrollArea();
  1050.                     break;
  1051.             }
  1052.           }
  1053.     }
  1054.     
  1055. /*-----------------------------------------------------------------*/
  1056.  
  1057.     void CPPScrollArea::DoHScroller (Point clickPt, short part)
  1058.     /* Handle a click in the horizontal scroll bar */
  1059.     {
  1060.         long    Result;
  1061.  
  1062.         gCurrentArea = this;
  1063.         
  1064.         if (this->HScroll)
  1065.           {
  1066.             switch (part) {
  1067.                 case inUpButton     :
  1068.                     Result = TrackControl(this->HScroll, clickPt, 
  1069.                                           (ProcPtr)Scroll_Left);
  1070.                     break;
  1071.                 case inDownButton    :
  1072.                     Result = TrackControl(this->HScroll, clickPt, 
  1073.                                           (ProcPtr)Scroll_Right);
  1074.                     break;
  1075.                 case inPageUp        :
  1076.                     HPageScroll (part, -1);
  1077.                     break;
  1078.                 case inPageDown        :
  1079.                     HPageScroll (part, 1);
  1080.                     break;
  1081.                 case inThumb        :
  1082.                     TrackControl (this->HScroll, clickPt, NULL);
  1083.                     MoveScrollArea();
  1084.                     break;
  1085.             }
  1086.           }
  1087.     }
  1088.  
  1089. /*-----------------------------------------------------------------*/
  1090.  
  1091.     void    CPPScrollArea::MakeCPPScrollArea (CPPWindow *OurWindow, 
  1092.                                               Rect *ViewArea, 
  1093.                                               Rect *DestArea, 
  1094.                                                  Boolean UseHScroll, 
  1095.                                                  Boolean UseVScroll,
  1096.                                                  short    hStep, 
  1097.                                                  short vStep)
  1098.     {
  1099.         Rect    tempRect;
  1100.         
  1101.         // set the control step size
  1102.         this->hStep = hStep;
  1103.         this->vStep = vStep;
  1104.         
  1105.         this->newClip = this->oldClip = NULL;
  1106.         
  1107.         this->isDragging = FALSE;
  1108.         this->needsErase = FALSE;
  1109.         
  1110.         /* figure out where the area and view rectangles are */
  1111.         this->destRect = *DestArea;
  1112.         this->areaRect = *ViewArea;
  1113.         this->areaRect.right -= (UseVScroll) ? 15 : 0;
  1114.         this->areaRect.bottom -= (UseHScroll) ? 15 : 0;
  1115.         SetRect (&this->viewRect, 0, 0, 
  1116.                  areaRect.right - areaRect.left,    
  1117.                  areaRect.bottom - areaRect.top);
  1118.         this->selRect = kEmptyRect;
  1119.         this->hasSelection = FALSE;
  1120.         
  1121.         // create the vertical scroll bar
  1122.         if (UseVScroll)
  1123.           {
  1124.               SetRect (&tempRect, areaRect.right, areaRect.top-1,
  1125.                        areaRect.right + 16, areaRect.bottom+1);
  1126.               this->VScroll = NewControl (OurWindow->GetWindow(),
  1127.                                           &tempRect, "\pVScroll",
  1128.                                           TRUE, 0, 0, 
  1129.                                           AreaHeight() - ViewHeight(),
  1130.                                           scrollBarProc, 13);
  1131.           }
  1132.         else this->VScroll = NULL;
  1133.           
  1134.         // create the horizontal scroll bar
  1135.         if (UseHScroll)
  1136.           {
  1137.               SetRect (&tempRect, areaRect.left-1, areaRect.bottom,
  1138.                        areaRect.right+1, areaRect.bottom + 16);
  1139.               this->HScroll = NewControl (OurWindow->GetWindow(),
  1140.                                           &tempRect, "\pHScroll",
  1141.                                           TRUE, 0, 0, 
  1142.                                           AreaWidth() - ViewWidth(),
  1143.                                           scrollBarProc, 13);
  1144.           }
  1145.         else this->HScroll = NULL;
  1146.                   
  1147.     }
  1148.     
  1149.     
  1150.     
  1151.     
  1152.     
  1153.